/**
 * @param {Point} [topLeft]
 * @param {Point} [bottomRight]
 * @constructor
 */
function Rectangle(topLeft, bottomRight)
{
	"use strict";
	/** @type {Rectangle} */
	var _this = this;
	/** @type {Point} */
	this.topLeft = topLeft ? topLeft : new Point();
	/** @type {Point} */
	this.bottomRight = bottomRight ? bottomRight : new Point();

	/**
	 * @param {!Rectangle} other
	 */
	this.copyTo = function(other)
	{
		other.topLeft = _this.topLeft.clone();
		other.bottomRight = _this.bottomRight.clone();
	}
}

/**
 * @param {Number} [x]
 * @param {Number} [y]
 * @constructor
 */
function Point(x, y)
{
	"use strict";

	/** @type {Point} */
	var _this = this;
	/** @type {Number} */
	this.X = x ? x : 0;
	/** @type {Number} */
	this.Y = y ? y : 0;

	/**
	 * Distance to other point
	 * @param {Point} other
	 * @return {Number}
	 */
	this.distance = function(other)
	{
		var xDiff = other.X - _this.X;
		var yDiff = other.Y - _this.Y;
		return Math.sqrt(xDiff*xDiff + yDiff*yDiff);
	};

	/**
	 * Whether point is inside rectangle
	 * @param {Rectangle} r
	 * @return {Boolean}
	 */
	this.inside = function(r)
	{
		return _this.X >= r.topLeft.X
			&& _this.X <= r.bottomRight.X
			&& _this.Y >= r.topLeft.Y
			&& _this.Y <= r.bottomRight.Y;
	};

	/**
	 * @return {Point}
	 */
	this.clone = function()
	{
		return new Point(_this.X, _this.Y);
	}
}

/**
 * Minimum and maxumum top-left values
 * @constructor
 * @extends {Rectangle}
 */
function Boundary()
{
	"use strict";

	/** @type {Number} */
	this.minLeft = this.topLeft.X;
	/** @type {Number} */
	this.maxLeft = this.bottomRight.X;
	/** @type {Number} */
	this.minTop = this.bottomRight.Y;
	/** @type {Number} */
	this.maxTop = this.topLeft.Y;

	/**
	 * Properties in ordered array
	 * @return {Array.<Number>}
	 */
	this.toArray = function()
	{
		return [this.minLeft, this.minTop, this.maxLeft, this.maxTop];
	};
}
Boundary.inherit(Rectangle);

/**
 * @constructor
 */
function Placement()
{
	"use strict";

	/** @type {Number} */
	this.width = NaN;
	/** @type {Number} */
	this.height = NaN;
	/** @type {Number} */
	this.left = NaN;
	/** @type {Number} */
	this.top = NaN;

	/**
	 * Whether position is undefined
	 * @return {Boolean}
	 */
	this.isEmpty = function()
	{
		return isNaN(this.width)
			&& isNaN(this.height)
			&& isNaN(this.left)
			&& isNaN(this.top);
	};

	/**
	 * Delete properties with non-numeric values;
	 * @return {Placement}
	 */
	this.clean = function()
	{
		if (this.isEmpty())
		{
			return null;
		}
		else
		{
			if (isNaN(this.width)) { delete this.width; }
			if (isNaN(this.height)) { delete this.height; }
			if (isNaN(this.left)) { delete this.left; }
			if (isNaN(this.top)) { delete this.top; }

			return this;
		}
	};
}